package com.yanqu.road.server.gameplayer.module.activity.cat;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.dao.impl.activity.cat.CatUserDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ValueParamArgs;
import com.yanqu.road.entity.activity.cat.*;
import com.yanqu.road.entity.activity.cat.config.CatLottery;
import com.yanqu.road.entity.activity.cat.config.CatMissionInfo;
import com.yanqu.road.entity.activity.cat.config.CatNpcInfo;
import com.yanqu.road.entity.activity.cat.config.CatSword;
import com.yanqu.road.entity.activity.cat.data.CatUserData;
import com.yanqu.road.entity.activity.seasontask.SeasonTaskConditionData;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.ePlayerAttrType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.*;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.activity.CatProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.cat.action.BaseElementAction;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.VipMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.cat.CatMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.pb.CatActivityPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class CatModule extends GeneralModule {

    CatUserData userData;

    //当前是否引导过
    boolean guide = false;

    public CatModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = CatMgr.getActivityInfo();
        if(ActivityMgr.activityInShowTime(activityInfo)) {
            userData = new CatUserDataDaoImpl().getCatUserData(activityInfo.getActivityId(), player.getUserId());
            if(userData != null){
                guide = userData.getGameTimes() > 0;
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if(userData != null){
            if(userData.isInsertOption()){
                new CatUserDataDaoImpl().add(userData);
            }else if(userData.isUpdateOption()){
                new CatUserDataDaoImpl().update(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {

        if (!SystemOpenMgr.systemOpen(player, eSystemId.CatActivity.getValue())) {
            return;
        }

        syncConfig();

        if(!resetOneDay()) {
            syncUserData();
        }
    }

    public void syncUserData() {

        CatActivityConfig config = CatMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        if(SystemOpenMgr.systemOpen(player, eSystemId.CatActivity.getValue())){
            if(userData == null || userData.getActivityId() != CatMgr.getActivityId()){
                initUserData();
            }
        }

        if(userData == null){
            return;
        }
        recoveryEnergy();

        CatProto.CatUserDataSync.Builder syncMsg = CatProto.CatUserDataSync.newBuilder();
        syncMsg.setUserData(CatActivityPb.parseUserData(userData));
        //CatMgr.getLogger().info("+++++++++++++ 下发玩家 {}数据 {}", player.getUserId(), userData.getActivityId());
        player.sendPacket(Protocol.U_CAT_SYNC_DATA, syncMsg);

    }

    public void syncConfig() {

        CatActivityConfig config = CatMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        CatProto.CatActivityConfigSync.Builder configSync = CatProto.CatActivityConfigSync.newBuilder();
        for (CatMissionInfo missionInfo : config.getMissionInfoList()) {
            configSync.addMission(CatActivityPb.parseCatMissionTemp(missionInfo, player.getLanguage()));
        }
        for (CatNpcInfo npcInfo : config.getNpcInfoList()) {
            configSync.addNpc(CatActivityPb.parseCatNpcTemp(npcInfo, player.getLanguage()));
        }
        for (CatLottery lottery : config.getLotteryList()) {
            configSync.addLottery(CatActivityPb.parseCatLotteryTemp(lottery, player.getLanguage()));
        }
        for (CatSword sword : config.getSwordList()) {
            configSync.addSword(CatActivityPb.parseCatSword(sword, player.getLanguage()));
        }

        player.sendPacket(Protocol.U_CAT_SYNC_CONFIG, configSync);
    }

    public boolean resetOneDay(){
        return false;
    }

    /**
     * 初始化玩家数据
     */
    public synchronized void initUserData() {
        // 系统未解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.CatActivity.getValue())) {
            return;
        }

        // 没有活动
        if (!ActivityMgr.activityInShowTime(CatMgr.getActivityInfo()) || CatMgr.getConfig() == null) {
            return;
        }

        ActivityInfo activityInfo = CatMgr.getActivityInfo();

        // 已经有数据了
        if (userData != null && userData.getActivityId() == activityInfo.getActivityId()) {
            return;
        }

        CatActivityConfig config = CatMgr.getConfig();

        CatUserData tmpUserData = new CatUserData();
        tmpUserData.setActivityId(activityInfo.getActivityId());
        tmpUserData.setUserId(player.getUserId());
        tmpUserData.setEnergy(config.getENERGY_INIT());
        tmpUserData.setLastRecTime(System.currentTimeMillis());
        tmpUserData.setPassStarMap(new HashMap<>());
        GameData tempGameData = initGameData(null, config, 0, false);
        tempGameData.setSettle(true);
        tmpUserData.setCellData(initElements(tmpUserData, config, tempGameData, false));
        tmpUserData.setGameData(tempGameData);
        tmpUserData.setAbilityLv(1);
        tmpUserData.setAbility(1);

        int historyPassId = (int)player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.CatActivityMaxPassId);
        tmpUserData.setHistoryPassId(historyPassId);
        CatSword sword = config.getCatSwordByLevel(tmpUserData.getAbilityLv());
        if(sword != null){
            tmpUserData.setAbility(sword.getAtk());
        }
        tmpUserData.setInsertOption();
        userData = tmpUserData;

    }

    /**
     * 初始关卡基础信息
     */
    private GameData initGameData(CatUserData catUserData, CatActivityConfig config, int missionId, boolean testMode) {
        CatMissionInfo missionInfo = config.getCatMissionInfoById(missionId);
        if(missionInfo == null){
            missionInfo = config.getMissionInfoList().get(0);
        }
        GameData old = null;
        if(catUserData != null){
            old = catUserData.getGameData();
        }
        GameData gameData = new GameData();
        gameData.setPass(missionInfo.getId());
        gameData.setAllRound(StringUtils.stringToIntegerList(missionInfo.getRoundsNumber(), "\\|").get(0));
        gameData.setRoleX(CatActivityConfig.ROLE_INIT_X);
        gameData.setRoleY(CatActivityConfig.ROLE_INIT_Y);
        gameData.setRoleBlood(config.getPLAYER_HP_INIT());
        gameData.setStartTime(System.currentTimeMillis());
        gameData.setRound(1);
        if("-1".equals(missionInfo.getBossPower())){
            gameData.setBossBlood(Long.MAX_VALUE);
        }else {
            gameData.setBossBlood(Long.valueOf(missionInfo.getBossPower()));
        }
        Random random = new Random();
        //bossId多个时，需要缓存
        List<Integer> bossIdList = StringUtils.stringToIntegerList(missionInfo.getBossId(), "\\|");
        if(bossIdList.size() > 1){
            int idx = random.nextInt(bossIdList.size());
            gameData.setBossId(String.valueOf(bossIdList.get(idx)));
        }

        //达摩随机的颜色如果多个，则要缓存
        List<String> dharmaList = StringUtils.stringToStringList(missionInfo.getDharma(), "#");
        if(dharmaList.size() > 1){
            int idx = random.nextInt(dharmaList.size());
            gameData.setDharma(dharmaList.get(idx));
        }

        //第一次玩，引导时需要初始怒气值,练习模式
        if(testMode && catUserData != null && catUserData.getGameTimes() == 0){
            gameData.setAngerBar(config.getCAT_GUIDE_INIT_ANGER());
        }
        if(old != null){

        }
        return gameData;
    }

    /**
     * 初始盘面
     */
    public Element[][] initElements(CatUserData data, CatActivityConfig config, GameData tempGameData, boolean testMode){
        Element[][] elements = new Element[CatActivityConfig.ROW_NUM][CatActivityConfig.COLUMN_NUM];
        CatMissionInfo missionInfo = config.getCatMissionInfoById(tempGameData.getPass());
        if(missionInfo == null){
            return null;
        }
        //主角元素
        Element roleElement = new Element(CatActivityConfig.ROLE_INIT_X, CatActivityConfig.ROLE_INIT_Y);
        roleElement.setType(eElementTypes.Role.getType());
        roleElement.setVal(config.getPLAYER_HP_INIT());
        elements[CatActivityConfig.ROLE_INIT_X][CatActivityConfig.ROLE_INIT_Y] = roleElement;

        //初始地形
        initTerrain(elements, data, config, missionInfo, tempGameData);

        if(!StringUtils.isNullOrEmpty(missionInfo.getInitTerrain()) && !"0".equals(missionInfo.getInitTerrain())) {
            //初始盘面改成固定(小怪+达摩)
            initFixedElements(elements, data, config, missionInfo, tempGameData);
        }else {
            //初始关卡小怪（配置随机）
            initMonster(elements, data, config, missionInfo, tempGameData);

            //初始达摩（配置随机）
            initElementValue(elements, data, config, missionInfo, tempGameData);
        }


        //引导数据生成,只有新手模式
        if(testMode) {
            initGuideData(elements, data, config, missionInfo, tempGameData);
        }

        //达摩愤怒
        angerDharma(elements, data, config, missionInfo, tempGameData);

        checkElementAllInit(elements);

        //检测主角周围是否可连接
        List<Element> tempList = CatMgr.getEightDirection(elements, new Position(CatActivityConfig.ROLE_INIT_X, CatActivityConfig.ROLE_INIT_Y));
        int i = 0;
        for (Element element : tempList) {
            if(CatMgr.isBlock(element)){
                i++;
            }
        }
        if(i == tempList.size()){
            CatMgr.getLogger().info("Cat Activity role disconnected, recall once : {}", player.getUserId());
            return initElements(data, config, tempGameData, testMode);
        }

        return elements;
    }

    //初始盘面改成固定(小怪+达摩)
    private void initFixedElements(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        List<String> eleStrList = StringUtils.stringToStringList(missionInfo.getInitTerrain(), "\\|");
        for (String eleStr : eleStrList) {
            List<String> paramList = StringUtils.stringToStringList(eleStr, "=");
            if(paramList.size() != 2){
                continue;
            }
            initSingleElement(elements, config, paramList);
        }
        //补充达摩
        initElementValue(elements, data, config, missionInfo, tempGameData);
    }

    private void initSingleElement(Element[][] elements, CatActivityConfig config, List<String> paramList) {
        List<Integer> position = StringUtils.stringToIntegerList(paramList.get(0), ",");
        List<Integer> typeValue = StringUtils.stringToIntegerList(paramList.get(1), "#");
        //CatMgr.getLogger().info("============== {}", StringUtils.listToString(typeValue, "#"));
        Element element = new Element(position.get(0), position.get(1));
        element.setId(typeValue.get(0));
        if (typeValue.size() > 1) {
            element.setVal(typeValue.get(1));
        }
        if(typeValue.size() > 2){
            int idx = typeValue.get(2);
            List<Integer> buffVal = StringUtils.stringToIntegerList(config.getBuffList().get(idx), ";");
            element.setVal(element.getVal() + buffVal.get(0));
            element.setColor(idx);
        }
        CatNpcInfo npcInfo = config.getCatNpcInfoById(element.getId());
        if (npcInfo == null) {
            return;
        }
        if (element.getId() < 1999) {
            element.setType(eElementTypes.Dharma.getType());
            element.setColor(CatMgr.getElementColor(element.getId()));
        } else {
            element.setType(eElementTypes.Monster.getType());

            //小怪有存活属性
            EleAttr attr = new EleAttr(eElementAttrTypes.Survive.getType(), 0);
            element.getAttrs().add(attr);
        }
        elements[element.getX()][element.getY()] = element;
    }

    //初始新手引导需要的数据
    private void initGuideData(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        if(data != null && data.getGameTimes() == 0){
            //坐标，怪物id#怪物血量|坐标，达摩id
            List<String> eleStrList = StringUtils.stringToStringList(config.getCAT_GUIDE_INIT_TERRAIN(), "\\|");
            for (String eleStr : eleStrList) {
                List<String> paramList = StringUtils.stringToStringList(eleStr, "=");
                if(paramList.size() != 2){
                    continue;
                }
                initSingleElement(elements, config, paramList);
            }
        }
    }

    /**
     * 初始地形
     */
    private void initTerrain(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        if(StringUtils.isNullOrEmpty(missionInfo.getTerrain())){
            return;
        }
        if("0".equals(missionInfo.getTerrain())){
            return;
        }
        List<String> terrainList = StringUtils.stringToStringList(missionInfo.getTerrain(), "\\|");
        //先随机属性颜色
        List<Integer> colorList = getJailColor(missionInfo.getJailColor());
        int colorGetIndex = 0;
        for (String terrain : terrainList) {
            List<String> paramsList = StringUtils.stringToStringList(terrain,"=");
            //元素位置
            List<Integer> elePosition = StringUtils.stringToIntegerList(paramsList.get(0), ",");
            Element element = elements[elePosition.get(0)][elePosition.get(1)];
            if(element == null) {
                element = new Element(elePosition.get(0), elePosition.get(1));
                elements[element.getX()][element.getY()] = element;
            }
            //元素属性
            List<Integer> attrList = StringUtils.stringToIntegerList(paramsList.get(1), "#");
            EleAttr eleAttr = new EleAttr();
            eleAttr.setId(attrList.get(0));
            if(attrList.size() > 1){
                eleAttr.setVal(attrList.get(1));
            }
            eleAttr.setType(CatMgr.getElementAttrType(eleAttr.getId()));
            element.getAttrs().add(eleAttr);
            //元素属性颜色
            if(!StringUtils.isNullOrEmpty(missionInfo.getJailColor())){
                if(colorList.size() > colorGetIndex){
                    eleAttr.setColor(colorList.get(colorGetIndex++));
                }
            }
            //监牢一定是万能格子
            if(CatMgr.hasAttr(element, eElementAttrTypes.Prison.getType()) != null){
                element.setType(eElementTypes.Omnipotent.getType());
            }
        }

        //重置无阻碍效果
        for (Element[] row : elements) {
            for (Element element : row) {
                if(element != null && CatMgr.needInit(element)){
                    element.setType(eElementTypes.NotNull.getType());
                }
            }
        }
    }

    /**
     * 初始小怪
     */
    private void initMonster(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        List<Integer> randomIndex = CatMgr.getRandomElementIndex();
        //随机小怪
        List<Element> monsterElementList = CatMgr.randomMonsterElement(config, missionInfo, false);
        //首次游戏，引导，不需要有小怪
        if(data != null && data.getGameTimes() == 0){
            return;
        }
        Random random = new Random();
        while (randomIndex.size() > 0 && monsterElementList.size() > 0){
            int indexNum = randomIndex.remove(0);
            Position position = CatMgr.coordinate(indexNum);
            if(CatMgr.isValid(position)) {
                Element element = elements[position.getX()][position.getY()];
                //八个方向如果有小怪，就再随机
                boolean continually = false;
                List<Element> elementList = CatMgr.getEightDirection(elements, position);
                for (Element ele : elementList) {
                    if(ele.getType() == eElementTypes.Monster.getType()){
                        continually = true;
                        break;
                    }
                }
                if(continually){
                    continue;
                }
                if (element != null && element.getType() != eElementTypes.NotNull.getType()) {
                    continue;
                }
                //香料盒子只能是达摩
                if (element != null && CatMgr.hasAttr(element, eElementAttrTypes.SpiceBox.getType()) != null){
                    continue;
                }
                //可以生成在电车上
                if (element != null && CatMgr.hasAttr(element, eElementAttrTypes.Tram.getType()) == null){
                    continue;
                }
                if(element == null){
                    element = new Element(position.getX(), position.getY());
                    elements[position.getX()][position.getY()] = element;
                }
                Element temp = monsterElementList.remove(0);

                CatMgr.initMonsterElement(config, random, element, temp);
            }
        }
    }

    /**
     * 初始元素(达摩)
     */
    private void initElementValue(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        List<Integer> idList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        List<String> itemList;
        if(!StringUtils.isNullOrEmpty(tempGameData.getDharma())){
            itemList = StringUtils.stringToStringList(tempGameData.getDharma(), "\\|");
        }else {
            itemList = StringUtils.stringToStringList(missionInfo.getDharma(), "\\|");
        }
        for (String s : itemList) {
            List<Integer> list = StringUtils.stringToIntegerList(s, ";");
            idList.add(list.get(0));
            weightList.add(list.get(1));
        }
        Random random = new Random();
        for (int i = 0; i < CatActivityConfig.ROW_NUM; i++) {
            for (int k = 0; k < CatActivityConfig.COLUMN_NUM; k++) {
                Element element = elements[i][k];
                //主角或者障碍物、小怪  不用初始化
                if(element != null && element.getType() != eElementTypes.NotNull.getType()){
                    continue;
                }
                if(element == null){
                    element = new Element(i, k);
                    elements[i][k] = element;
                }
                //初始达摩
                element.setType(eElementTypes.Dharma.getType());
                int idx = RandomHelper.getRandomIndexByWeight(weightList, random);
                element.setId(idList.get(idx));
                element.setColor(CatMgr.getElementColor(element.getId()));
                //CatMgr.getLogger().info("------------- Dharma init {}，x {}, y {}, cox {} ", JSONObject.toJSONString(element), i, k, CatMgr.getIndex(new Position(i, k)));
            }
        }
    }

    /**
     * 愤怒达摩
     * @param data  预留，未使用
     */
    private void angerDharma(Element[][] elements, CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        List<Integer> randomIndex = CatMgr.getRandomElementIndex();

        //达摩愤怒数量
        int angerNum = getAngerNum(data, config, missionInfo, tempGameData);
        //CatMgr.getLogger().info("---- 达摩愤怒 : {}", angerNum);
        int loop = 100;
        while (angerNum > 0 && randomIndex.size() > 0){
            loop--;
            if(loop <= 0){
                break;
            }
            int indexNum = randomIndex.remove(0);
            Position position = CatMgr.coordinate(indexNum);
            if(CatMgr.isValid(position)){
                Element element = elements[position.getX()][position.getY()];
                if(element == null){
                    continue;
                }
                if(element.getType() != eElementTypes.Dharma.getType()){
                    continue;
                }
                if(CatMgr.hasAttr(element, eElementAttrTypes.Anger.getType()) != null){
                    continue;
                }
                EleAttr attr = new EleAttr();
                attr.setType(eElementAttrTypes.Anger.getType());
                element.getAttrs().add(attr);
                //CatMgr.getLogger().info("---- 达摩愤怒 : {}", JSONObject.toJSONString(element));
                angerNum--;
            }
        }
    }

    /**
     * 随机不重复的监牢颜色
     */
    public List<Integer> getJailColor(String jailColor){
        if(StringUtils.isNullOrEmpty(jailColor) || "0".equals(jailColor)){
            return new ArrayList<>();
        }
        List<Integer> result = new ArrayList<>();
        //最大循环次数
        int loop = 10000;
        //颜色数量（最大盘面格子数）
        int max = CatActivityConfig.ROW_NUM * CatActivityConfig.COLUMN_NUM;
        Random random = new Random();
        List<Integer> keyList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        List<String> itemList = StringUtils.stringToStringList(jailColor, "\\|");
        for (String s : itemList) {
            List<Integer> keyWeight = StringUtils.stringToIntegerList(s, ";");
            keyList.add(keyWeight.get(0));
            weightList.add(keyWeight.get(1));
        }
        while (result.size() < max && loop > 0){
            loop--;
            int idx = RandomHelper.getRandomIndexByWeight(weightList, random);
            int val = keyList.get(idx);
            boolean exist = false;
            //最大连续不重复（如：3种颜色，不等于前两种，即满足）
            int k = keyList.size() - 1;
            for (int i = result.size() - 1; i >= 0; i--) {
                k--;
                if(result.get(i) == val){
                    exist = true;
                    break;
                }
                if(k == 0){
                    break;
                }
            }
            if(!exist){
                result.add(val);
            }
        }
        return result;
    }

    /**
     * 获取愤怒达摩数量
     */
    private int getAngerNum(CatUserData data, CatActivityConfig config, CatMissionInfo missionInfo, GameData tempGameData) {
        int round = tempGameData.getRound();
        if(StringUtils.isNullOrEmpty(missionInfo.getDharmaAngerNumber())){
            return 0;
        }
        List<String> itemList = StringUtils.stringToStringList(missionInfo.getDharmaAngerNumber(), "\\|");
        String weightItem = null;
        for (String str : itemList) {
            List<String> list = StringUtils.stringToStringList(str, "=");
            if(round >= Integer.valueOf(list.get(0))){
                weightItem = list.get(1);
            }
        }
        if(weightItem == null){
            return 0;
        }
        List<Integer> keyList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        List<String> list = StringUtils.stringToStringList(weightItem, ";");
        for (String s : list) {
            List<Integer> valList = StringUtils.stringToIntegerList(s, ",");
            keyList.add(valList.get(0));
            weightList.add(valList.get(1));
        }
        int idx = RandomHelper.getRandomIndexByWeight(weightList);
        if(idx == -1){
            return 0;
        }
        return keyList.get(idx);
    }

    /**
     * 连线
     */
    public int connect(List<Position> positionList) {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        recoveryEnergy();

        if(userData.getGameData().isSettle()){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_DONE;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(userData.getGameData().getPass());
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }
        Position rolePosition = new Position(userData.getGameData().getRoleX(), userData.getGameData().getRoleY());

        //连线中的点不可重复
        List<Position> es = new ArrayList<>(positionList);

        es.add(rolePosition);
        if (checkConnectPositionValid(es)) return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;

        //复制盘面
        Element[][] tempElements = CatMgr.copy(userData.getCellData());
        GameData tempStatus = CatMgr.copy(userData.getGameData());

        //校验路径是否可达
        ConnectResult result = connect(rolePosition, positionList, tempElements, tempStatus, missionInfo);
        if(result.getRet() != 0){
            return result.getRet();
        }

        if(result.isEnd()){
            //结算
            result.getGameData().setSettle(true);
        }else {
            //盘面填充
            //加达摩
            initElementValue(result.getElements(), userData, config, missionInfo, tempStatus);

            //达摩愤怒
            angerDharma(result.getElements(), userData, config, missionInfo, result.getGameData());

            checkElementAllInit(result.getElements());

            //回合数+1
            tempStatus.setRound(tempStatus.getRound() + 1);
        }

        SettleResult settleResult = new SettleResult();

        if(result.getGameData().isSettle()){
            int passId = result.getGameData().getPass();


            if(result.getGameData().isWin()){

                calWinRewards(missionInfo, result.gameData, settleResult);

                if(settleResult.getStar() > 0) {
                    userData.getPassStarMap().put(passId, settleResult.getStar());
                }

            }else {
                //输了
                //失败奖励
                settleResult.getReward().addProperty(PropertyHelper.parseStringToProperty(missionInfo.getFailRewards()));
            }

            player.getModule(CurrencyModule.class).addCurrency(settleResult.getReward(), eLogMoneyType.CatActivity, eLogMoneyType.CatActivityChallengePassReward);

            //积分
            int score = settleResult.getReward().getCountByGoodsId(config.getSCORE_ITEM_ID()).intValue();
            if(score > 0){
                userData.setScore(userData.getScore() + score);
                AutoLogMgr.add(new LogCatActivityScore(player.getUserId(), userData.getActivityId(), score, userData.getScore()));
            }

            //关卡+积分
            int rankPassId = 0;
            if(result.getGameData().isWin()){
                rankPassId = getPassRankValue(config, result.getGameData().getPass());
            }
            player.notifyListener(eGamePlayerEventType.CatActivityPassRank.getValue(), new ValueParamArgs(rankPassId, userData.getScore() + ""));

            //更新历史最高
            int historyPassId = (int)player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.CatActivityMaxPassId);
            if(result.getGameData().getPass() > historyPassId && result.getGameData().getPass() != config.getXinMoPassId()){
                player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.CatActivityMaxPassId, result.getGameData().getPass());
            }
        }

        //最高伤害（避免活动结束，未结算）
        if(!StringUtils.isNullOrEmpty(result.getGameData().getBossId())) {
            if (result.getGameData().getDamage() > userData.getDamage()) {
                userData.setDamage(result.getGameData().getDamage());
                player.notifyListener(eGamePlayerEventType.CatActivityDamageRank.getValue(), new ValueParamArgs(userData.getDamage(), ""));
            }
        }

        userData.setCellData(result.getElements());
        userData.setGameData(result.getGameData());

        CatProto.CatGameConnectRespMsg.Builder respMsg = CatProto.CatGameConnectRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(settleResult.getReward()));
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        for (CatProto.CatConnectDetailTemp.Builder builder : result.getDetailBuilderList()) {
            respMsg.addDetail(builder);
        }
        for (int index : result.getWanNengList()) {
            Position position = CatMgr.coordinate(index);
            respMsg.addOmnipotentPoint(CatActivityPb.parsePoint(position.getX(), position.getY()));
        }
        for (int index : result.getNewMonsterList()) {
            Position position = CatMgr.coordinate(index);
            respMsg.addMonsterPoint(CatActivityPb.parsePoint(position.getX(), position.getY()));
        }
        for (CatProto.CatGameMoveHistoryTemp.Builder builder : result.getMoveList()) {
            respMsg.addMove(builder);
        }
        player.sendPacket(Protocol.U_CAT_CONNECTION, respMsg);

        //星级升级日志
        if(settleResult.getStar() > 0) {
            AutoLogMgr.add(new LogCatActivityUpgrade(userData.getUserId(),
                    userData.getActivityId(),
                    2,
                    getPassStar(userData.getPassStarMap()),
                    userData.getUseEnergy(),
                    userData.getGameTimes(),
                    System.currentTimeMillis() - userData.getGameData().getStartTime()
            ));
        }

        //结束日志
        if (result.isEnd()) {
            int endType = 0;
            if(result.getGameData().isWin()){
                endType = 1;
            }else if(result.getGameData().getRoleBlood() <= 0){
                endType = 2;
            }else if(result.getGameData().getAllRound() - result.getGameData().getRound() <= 0){
                endType = 3;
            }
            AutoLogMgr.add(new LogCatActivityPassEnd(userData.getUserId(),
                    userData.getActivityId(),
                    1,
                    userData.getGameData().getPass(),
                    missionInfo.getChapterId(),
                    missionInfo.getEnergyCost(),
                    userData.getUseEnergy(),
                    userData.getAbilityLv(),
                    endType,
                    settleResult.getThisStar(),
                    getPassStar(userData.getPassStarMap()),
                    userData.getGameData().getRound(),
                    JSONObject.toJSONString(userData.getGameData().getRoleBloodLose()),
                    JSONObject.toJSONString(userData.getGameData().getMonsterSkill()),
                    userData.getGameData().getSkillDamage(),
                    userData.getGameData().getMonsterDamage(),
                    Long.parseLong(missionInfo.getBossPower()),
                    userData.getGameData().getBossBlood(),
                    userData.getGameData().getAllConnect(),
                    System.currentTimeMillis() - userData.getGameData().getStartTime(),
                    PropertyHelper.parsePropertyToString(settleResult.getReward())
                    ));
        }
        return 0;
    }

    public boolean checkConnectPositionValid(List<Position> es) {
        if (CatMgr.isRepeat(es)) {
            return true;
        }

        //检验位置是否有效(7*7边界)
        for (Position position : es) {
            if (!CatMgr.isValid(position)) {
                return true;
            }
        }
        return false;
    }

    public int getPassStar(Map<Integer, Integer> passStarMap) {
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : passStarMap.entrySet()) {
            count += entry.getValue();
        }
        return count;
    }

    public int getMaxPass(Map<Integer, Integer> passStarMap) {
        int max = 0;
        for (Map.Entry<Integer, Integer> entry : passStarMap.entrySet()) {
           if(entry.getKey() > max){
               max = entry.getKey();
           }
        }
        return max;
    }

    public void calWinRewards(CatMissionInfo missionInfo, GameData status, SettleResult settleResult) {
        int star = userData.getPassStarMap().getOrDefault(missionInfo.getId(), 0);
        boolean first = star == 0;
        settleResult.setFirst(false);
        //赢了
        if(first){
            //首通奖励
            if(!StringUtils.isNullOrEmpty(missionInfo.getRewards()) && !"0".equals(missionInfo.getRewards())) {
                settleResult.getReward().addProperty(PropertyHelper.parseStringToProperty(missionInfo.getRewards()));
            }
        }
        //固定奖励
        settleResult.getReward().addProperty(PropertyHelper.parseStringToProperty(missionInfo.getSuccessRewards()));
        //随机奖励
        settleResult.getReward().addProperty(PropertyHelper.parseStringToProperty(CatMgr.getMissionRandomReward(missionInfo.getSuccessRandomRewards())));

        //星级
        int newStar = CatMgr.getPassStar(status.getRound(), missionInfo);
        settleResult.setThisStar(newStar);
        if(newStar > star){
            settleResult.setStar(newStar);
        }
    }

    private ConnectResult connect(Position rolePosition, List<Position> positionList, Element[][] tempElements, GameData tempStatus, CatMissionInfo missionInfo) {
        ConnectResult result = new ConnectResult(rolePosition, positionList, tempElements, tempStatus, missionInfo, userData);

        CatActivityConfig config = CatMgr.getConfig();
        //CatMgr.getLogger().info("Cat Activity positionList ：{}", JSONObject.toJSONString(positionList));
        try{
            BaseElementAction action = BaseElementAction.getByType(eElementTypes.Role.getType());
            //是否可达
            boolean accept = action.acceptNext(result);
            if(accept){
                //执行连接消除
                action.connectNext(result);
            }
            if(result.getRet() != 0){
                return result;
            }

            //怒气值收集
            int anger = config.getBattleAddition(result.getAttackPoint());
            result.getGameData().setAngerBar(anger + result.getGameData().getAngerBar());
            if(result.getGameData().getAngerBar() > config.getCAT_PLAYER_SKILL_MAX_ANGER()){
                result.getGameData().setAngerBar(config.getCAT_PLAYER_SKILL_MAX_ANGER());
            }

            //小怪攻击boss的伤害
            long damage = 0;
            for (Element element : result.getDisappearList()) {
                if(element.getType() == eElementTypes.Monster.getType()){
                    List<Integer> buffVal = StringUtils.stringToIntegerList(config.getBuffList().get(element.getColor()), ";");
                    damage += BigDecimal.valueOf(userData.getAbility()).multiply(BigDecimal.valueOf(1000 + buffVal.get(1))).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
                    //CatMgr.getLogger().info("player {}, ability {} addition {} damage {}", player.getUserId(), userData.getAbility(), buffVal.get(1), damage);
                }
            }
            tempStatus.setMonsterDamage(tempStatus.getMonsterDamage() + damage);
            if(damage < tempStatus.getBossBlood()){
                tempStatus.setBossBlood(tempStatus.getBossBlood() - damage);
                tempStatus.setDamage(tempStatus.getDamage() + damage);
            }else {
                tempStatus.setBossBlood(0);
                tempStatus.setDamage(tempStatus.getDamage() + tempStatus.getBossBlood());
            }
            result.setDamage(damage);

            boolean end = false;
            //boss 没血量  结算
            if(tempStatus.isEnd()){
                end = true;
            }else {
                //地形变化
                action.changeNext(result);

                //达摩、小怪技能
                action.attackNext(result);

                if (result.getRet() != 0) {
                    return result;
                }

                //掉落
                action.generateNext(result);

                //主角没血量  回合结算
                if(tempStatus.isEnd()){
                    end = true;
                }
            }
            result.setEnd(end);
            result.getGameData().setAllConnect(result.getAttackPoint() + result.getGameData().getAllConnect());
//            CatMgr.getLogger().info("------- result, 结果: roleBlood:{}, bossBlood:{}, round {}/{}",
//                    result.getGameData().getRoleBlood(), result.getGameData().getBossBlood(), result.getGameData().getRound(), result.getGameData().getAllRound());
        }catch (CatConnectExcetpion e){
            result.setRet(e.getCode());
        }catch (Exception e1){
            CatMgr.getLogger().error(e1.getMessage(), e1);
            result.setRet(-1);
        }
        for (Element[] tempElement : tempElements) {
            for (Element element : tempElement) {
                if(CatMgr.hasAttr(element, eElementAttrTypes.Rail.getType()) != null) {
                    //CatMgr.getLogger().info("================== tempElements: {}", JSONObject.toJSONString(element));
                }
            }
        }
        return result;
    }

    /**
     * 挑战关卡
     */
    public int challenge(int passId) {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }
        if(userData.getActivityId() != CatMgr.getActivityId()){
            return GameErrorCode.E_GAME_ERROR;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(!userData.getGameData().isSettle()){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_GOING;
        }

        if(userData.getPassStarMap().size() == 0){
            passId = config.getMissionInfoList().get(0).getId();
        }else {
            if(passId == config.getXinMoPassId()){
                //心魔关卡需要过完普通模式-化猫后
                if(!userData.getPassStarMap().containsKey(config.getNormalLastPassId())){
                    return GameErrorCode.E_CAT_ACTIVITY_PASS_LOCK;
                }
            } else if(!userData.getPassStarMap().containsKey(passId) && !userData.getPassStarMap().containsKey(passId - 1)){
                return GameErrorCode.E_CAT_ACTIVITY_PASS_LOCK;
            }
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(passId);
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_ID_ERROR;
        }

        recoveryEnergy();

        // 体力
        if (userData.getEnergy() < missionInfo.getEnergyCost()) {
            return GameErrorCode.E_CAT_ACTIVITY_ENERGY_NO_ENOUGH;
        }

        reduceEnergy(missionInfo.getEnergyCost(), 1);

        GameData tempGameData = initGameData(userData, config, passId, false);
        Element[][] elements = initElements(userData, config, tempGameData, false);
        userData.setCellData(elements);
        userData.setGameData(tempGameData);
        //累计使用体力
        userData.setUseEnergy(userData.getUseEnergy() + missionInfo.getEnergyCost());
        userData.setGameTimes(userData.getGameTimes() + 1);

        CatProto.CatChallengePassRespMsg.Builder respMsg = CatProto.CatChallengePassRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        player.sendPacket(Protocol.U_CAT_CHALLENGE, respMsg);
        return 0;
    }

    /**
     * 放弃挑战
     */
    public int giveUp() {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData.getGameData().isSettle()){
           return GameErrorCode.E_CAT_ACTIVITY_PASS_DONE;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(userData.getGameData().getPass());
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        userData.getGameData().setSettle(true);
        userData.setUpdateOption();

        //结算
        Property reward = new Property();
        reward.addProperty(PropertyHelper.parseStringToProperty(missionInfo.getFailRewards()));

        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityGiveUpPassReward);

        //积分
        int score = reward.getCountByGoodsId(config.getSCORE_ITEM_ID()).intValue();
        if(score > 0){
            userData.setScore(userData.getScore() + score);
            AutoLogMgr.add(new LogCatActivityScore(player.getUserId(), userData.getActivityId(), score, userData.getScore()));

            player.notifyListener(eGamePlayerEventType.CatActivityPassRank.getValue(), new ValueParamArgs(0, userData.getScore() + ""));
        }

        CatProto.CatGameGiveUpPassRespMsg.Builder respMsg = CatProto.CatGameGiveUpPassRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        player.sendPacket(Protocol.U_CAT_GIVE_UP, respMsg);

        //结束日志
        AutoLogMgr.add(new LogCatActivityPassEnd(userData.getUserId(),
                userData.getActivityId(),
                1,
                userData.getGameData().getPass(),
                missionInfo.getChapterId(),
                missionInfo.getEnergyCost(),
                userData.getUseEnergy(),
                userData.getAbilityLv(),
                4,
                0,
                getPassStar(userData.getPassStarMap()),
                userData.getGameData().getRound(),
                JSONObject.toJSONString(userData.getGameData().getRoleBloodLose()),
                JSONObject.toJSONString(userData.getGameData().getMonsterSkill()),
                userData.getGameData().getSkillDamage(),
                userData.getGameData().getMonsterDamage(),
                Long.parseLong(missionInfo.getBossPower()),
                userData.getGameData().getBossBlood(),
                userData.getGameData().getAllConnect(),
                System.currentTimeMillis() - userData.getGameData().getStartTime(),
                PropertyHelper.parsePropertyToString(reward)
        ));
        return 0;
    }

    /**
     * 发动主角攻击
     */
    public int attackBoss() {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData.getGameData().isSettle()){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_DONE;
        }

        if(userData.getGameData().getAngerBar() < config.getPLAYER_SKILL_NEED_ANGER()){
            return GameErrorCode.E_CAT_ACTIVITY_ANGER_NO_ENOUGH;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(userData.getGameData().getPass());
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        //盘面是否有沉默的小怪
        List<Element> monsterList = CatMgr.getElementsByType(userData.getCellData(), eElementTypes.Monster.getType(), config, 5);
        if(monsterList.size() > 0){
            return GameErrorCode.E_CAT_ACTIVITY_ROLE_ACTION_LIMIT;
        }

        GameData status = userData.getGameData();

        int times = status.getAngerBar() / config.getPLAYER_SKILL_NEED_ANGER();

        status.setAngerBar(status.getAngerBar() - times * config.getPLAYER_SKILL_NEED_ANGER());

        long damage = BigDecimal.valueOf(userData.getAbility()).multiply(BigDecimal.valueOf(times))
                .multiply(BigDecimal.valueOf(config.getCAT_PLAYER_SKILL_ATK_PARAMETER())).divide(BigDecimal.valueOf(1000L), 0, BigDecimal.ROUND_UP).longValue();

        CatProto.CatRoleAttackRespMsg.Builder respMsg = CatProto.CatRoleAttackRespMsg.newBuilder();

        status.setSkillDamage(status.getSkillDamage() + damage);
        SettleResult settleResult = new SettleResult();
        if(status.getBossBlood() > damage){
            status.setBossBlood(status.getBossBlood() - damage);
            status.setDamage(status.getDamage() + damage);
        }else {
            status.setSettle(true);
            status.setDamage(status.getDamage() + status.getBossBlood());
            status.setBossBlood(0);
            //结算
            calWinRewards(missionInfo, userData.getGameData(), settleResult);

            if(settleResult.getStar() > 0) {
                userData.getPassStarMap().put(missionInfo.getId(), settleResult.getStar());
            }
            //奖励
            player.getModule(CurrencyModule.class).addCurrency(settleResult.getReward(), eLogMoneyType.CatActivity, eLogMoneyType.CatActivityChallengePassReward);
            respMsg.setReward(PropertyHelper.parsePropertyToString(settleResult.getReward()));

            //积分
            int score = settleResult.getReward().getCountByGoodsId(config.getSCORE_ITEM_ID()).intValue();
            if(score > 0){
                userData.setScore(userData.getScore() + score);
                AutoLogMgr.add(new LogCatActivityScore(player.getUserId(), userData.getActivityId(), score, userData.getScore()));
            }

            //关卡+积分
            player.notifyListener(eGamePlayerEventType.CatActivityPassRank.getValue(), new ValueParamArgs(getPassRankValue(config, userData.getGameData().getPass()), userData.getScore() + ""));
        }
        userData.setUpdateOption();

        //最高伤害（避免活动结束，未结算）
        if(!StringUtils.isNullOrEmpty(userData.getGameData().getBossId())) {
            if (userData.getGameData().getDamage() > userData.getDamage()) {
                userData.setDamage(userData.getGameData().getDamage());
                player.notifyListener(eGamePlayerEventType.CatActivityDamageRank.getValue(), new ValueParamArgs(userData.getDamage(), ""));
            }
        }

        respMsg.setRet(0);
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        player.sendPacket(Protocol.U_CAT_LAUNCH, respMsg);

        if (status.isSettle()) {
            //结束日志
            AutoLogMgr.add(new LogCatActivityPassEnd(userData.getUserId(),
                    userData.getActivityId(),
                    3,
                    userData.getGameData().getPass(),
                    missionInfo.getChapterId(),
                    missionInfo.getEnergyCost(),
                    userData.getUseEnergy(),
                    userData.getAbilityLv(),
                    1,
                    settleResult.getThisStar(),
                    getPassStar(userData.getPassStarMap()),
                    userData.getGameData().getRound(),
                    JSONObject.toJSONString(userData.getGameData().getRoleBloodLose()),
                    JSONObject.toJSONString(userData.getGameData().getMonsterSkill()),
                    userData.getGameData().getSkillDamage(),
                    userData.getGameData().getMonsterDamage(),
                    Long.parseLong(missionInfo.getBossPower()),
                    userData.getGameData().getBossBlood(),
                    userData.getGameData().getAllConnect(),
                    System.currentTimeMillis() - userData.getGameData().getStartTime(),
                    PropertyHelper.parsePropertyToString(settleResult.getReward())
            ));
        }
        return 0;
    }

    /**
     * 退魔剑升级
     */
    public int abilityUpgrade() {

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatSword sword = config.getCatSwordByLevel(userData.getAbilityLv());
        if(sword == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        CatSword next = config.getCatSwordByLevel(userData.getAbilityLv() + 1);
        if(next == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        if(sword.getCost() <= 0){
            return GameErrorCode.E_CAT_ACTIVITY_SWORD_MAX_LEVEL;
        }

        Property consume = PropertyHelper.parseStringToProperty(config.getKUNGFU_UPGRADE_ITEM_ID() + "=" + sword.getCost());
        if(!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.CatActivity, eLogMoneyType.CatActivitySwordConsume)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        userData.setAbility(next.getAtk());
        userData.setAbilityLv(next.getLevel());

        player.notifyListener(eGamePlayerEventType.CatActivitySwordLevel.getValue(), next.getLevel());

        CatProto.CatRoleAbilityUpgradeRespMsg.Builder respMsg = CatProto.CatRoleAbilityUpgradeRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        player.sendPacket(Protocol.U_CAT_ABILITY_UPGRADE, respMsg);

        //升级日志
        AutoLogMgr.add(new LogCatActivityUpgrade(userData.getUserId(),
                userData.getActivityId(),
                1,
                userData.getAbilityLv(),
                userData.getUseEnergy(),
                userData.getGameTimes(),
                userData.getGameData().isSettle() ? 0 : (System.currentTimeMillis() - userData.getGameData().getStartTime())
                ));

        return 0;
    }

    /**
     * 扫荡
     */
    public int mopUpPass(int passId, int times) {

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData.getActivityId() != CatMgr.getActivityId()){
            return GameErrorCode.E_GAME_ERROR;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        int star = userData.getPassStarMap().getOrDefault(passId, 0);
        //改为过关即可
        if(star == 0){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_NO_WOP_UP;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(passId);
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_ID_ERROR;
        }

        recoveryEnergy();

        int costEnergy = missionInfo.getEnergyCost() * times;
        // 体力
        if (userData.getEnergy() < costEnergy) {
            return GameErrorCode.E_CAT_ACTIVITY_ENERGY_NO_ENOUGH;
        }

        reduceEnergy(costEnergy, 2);

        //累计使用体力
        userData.setUseEnergy(userData.getUseEnergy() + costEnergy);
        userData.setGameTimes(userData.getGameTimes() + times);

        Property reward = new Property();
        for (int i = 0; i < times; i++) {
            //固定奖励
            reward.addProperty(PropertyHelper.parseStringToProperty(missionInfo.getSuccessRewards()));
            //随机奖励
            reward.addProperty(PropertyHelper.parseStringToProperty(CatMgr.getMissionRandomReward(missionInfo.getSuccessRandomRewards())));
        }

        //积分
        BigInteger score = reward.getCountByGoodsId(config.getSCORE_ITEM_ID());
        if(score.compareTo(BigInteger.ZERO) > 0){
            userData.setScore(userData.getScore() + score.intValue());
            AutoLogMgr.add(new LogCatActivityScore(player.getUserId(), userData.getActivityId(), score.intValue(), userData.getScore()));
        }

        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityMopUpPassReward);

        //关卡+积分
        player.notifyListener(eGamePlayerEventType.CatActivityPassRank.getValue(), new ValueParamArgs(getPassRankValue(config, passId), userData.getScore() + ""));

        CatProto.CatMopUpRespMsg.Builder respMsg = CatProto.CatMopUpRespMsg.newBuilder();
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        player.sendPacket(Protocol.U_CAT_MOPPING_UP, respMsg);


        //结束日志
        AutoLogMgr.add(new LogCatActivityPassEnd(userData.getUserId(),
                userData.getActivityId(),
                2,
                passId,
                missionInfo.getChapterId(),
                missionInfo.getEnergyCost(),
                userData.getUseEnergy(),
                userData.getAbilityLv(),
                0,
                0,
                getPassStar(userData.getPassStarMap()),
                userData.getGameData().getRound(),
                JSONObject.toJSONString(userData.getGameData().getRoleBloodLose()),
                JSONObject.toJSONString(userData.getGameData().getMonsterSkill()),
                userData.getGameData().getSkillDamage(),
                userData.getGameData().getMonsterDamage(),
                Long.parseLong(missionInfo.getBossPower()),
                userData.getGameData().getBossBlood(),
                userData.getGameData().getAllConnect(),
                System.currentTimeMillis() - userData.getGameData().getStartTime(),
                PropertyHelper.parsePropertyToString(reward)
        ));
        return 0;
    }

    public int getPassRankValue(CatActivityConfig config, int passId){
        if(config.getXinMoPassId() == passId){
            return 0;
        }
        return passId;
    }

    /**
     * 自动通关
     */
    public int fastThrough(int passId) {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }
        if(userData.getActivityId() != CatMgr.getActivityId()){
            return GameErrorCode.E_GAME_ERROR;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(passId == config.getXinMoPassId()){
            //心魔关卡无法自动通关
            return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
        }

        if(!userData.getGameData().isSettle()){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_GOING;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(passId);
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        //star == 0 是首次通关
        int star = userData.getPassStarMap().getOrDefault(passId, 0);

        if(userData.getHistoryPassId() == 0){
            return GameErrorCode.E_CAT_ACTIVITY_POWER_NO_ENOUGH;
        }

        if(userData.getHistoryPassId() < passId || userData.getAbility() < Integer.valueOf(missionInfo.getRecommendPower())){
            return GameErrorCode.E_CAT_ACTIVITY_POWER_NO_ENOUGH;
        }

        recoveryEnergy();

        int costEnergy = missionInfo.getEnergyCost();
        // 体力
        if (userData.getEnergy() < costEnergy) {
            return GameErrorCode.E_CAT_ACTIVITY_ENERGY_NO_ENOUGH;
        }

        userData.getPassStarMap().put(passId, 1);

        reduceEnergy(costEnergy, 2);

        //累计使用体力
        userData.setUseEnergy(userData.getUseEnergy() + costEnergy);
        userData.setGameTimes(userData.getGameTimes() + 1);

        //固定奖励
        Property reward = new Property();
        reward.addProperty(PropertyHelper.parseStringToProperty(missionInfo.getSuccessRewards()));
        //随机奖励
        reward.addProperty(PropertyHelper.parseStringToProperty(CatMgr.getMissionRandomReward(missionInfo.getSuccessRandomRewards())));
        if(star == 0){
            //首通奖励
            if(!StringUtils.isNullOrEmpty(missionInfo.getRewards()) && !"0".equals(missionInfo.getRewards())) {
                reward.addProperty(PropertyHelper.parseStringToProperty(missionInfo.getRewards()));
            }
        }

        //积分
        BigInteger score = reward.getCountByGoodsId(config.getSCORE_ITEM_ID());
        if(score.compareTo(BigInteger.ZERO) > 0){
            userData.setScore(userData.getScore() + score.intValue());
            AutoLogMgr.add(new LogCatActivityScore(player.getUserId(), userData.getActivityId(), score.intValue(), userData.getScore()));
        }

        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityAutoPassReward);

        //关卡+积分
        player.notifyListener(eGamePlayerEventType.CatActivityPassRank.getValue(), new ValueParamArgs(getPassRankValue(config, passId), userData.getScore() + ""));

        //盘面也要初始化（客户端为啥不屏蔽??）
        GameData tempGameData = initGameData(null, config, missionInfo.getId(), false);
        tempGameData.setSettle(true);
        userData.setCellData(initElements(userData, config, tempGameData, false));
        userData.setGameData(tempGameData);


        CatProto.CatFastThroughRespMsg.Builder respMsg = CatProto.CatFastThroughRespMsg.newBuilder();
        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));
        respMsg.setUserData(CatActivityPb.parseUserData(userData));
        respMsg.setRet(0);
        player.sendPacket(Protocol.U_CAT_FAST_THROUGH, respMsg);

        //结束日志
        AutoLogMgr.add(new LogCatActivityPassEnd(userData.getUserId(),
                userData.getActivityId(),
                4,
                userData.getGameData().getPass(),
                missionInfo.getChapterId(),
                missionInfo.getEnergyCost(),
                userData.getUseEnergy(),
                userData.getAbilityLv(),
                5,
                0,
                getPassStar(userData.getPassStarMap()),
                userData.getGameData().getRound(),
                JSONObject.toJSONString(userData.getGameData().getRoleBloodLose()),
                JSONObject.toJSONString(userData.getGameData().getMonsterSkill()),
                userData.getGameData().getSkillDamage(),
                userData.getGameData().getMonsterDamage(),
                Long.parseLong(missionInfo.getBossPower()),
                userData.getGameData().getBossBlood(),
                userData.getGameData().getAllConnect(),
                System.currentTimeMillis() - userData.getGameData().getStartTime(),
                PropertyHelper.parsePropertyToString(reward)
        ));
        return 0;
    }

    /**
     * 自然恢复体力
     */
    public void recoveryEnergy(){
        CatActivityConfig config = CatMgr.getConfig();
        if(userData != null && config != null){
            int logBeforeEnergy = userData.getEnergy();

            CalcPowerResult result = PowerHelper.calcPower(
                    userData.getLastRecTime() / 1000,
                    config.getENERGY_CD(),
                    config.getENERGY_CD_NUM(),
                    config.getENERGY_LIMIT(),
                    userData.getEnergy());
            userData.setEnergy(result.getCurPower());
            userData.setLastRecTime(result.getLastRecoverTime() * 1000);

            // 体力日志
            if (userData.getEnergy() != logBeforeEnergy) {
                log.debug("user {} set energy {}", player.getUserId(), result.getCurPower());
                AutoLogMgr.add(new LogCatActivityEnergy(userData.getUserId(), userData.getActivityId(), 4, userData.getEnergy() - logBeforeEnergy, userData.getEnergy()));
            }
        }
    }

    /**
     * 扣体力
     * @param way  1:正常，2：扫荡；
     */
    public boolean reduceEnergy(int count, int way) {

        if (userData.getEnergy() < count) {
            return false;
        }

        CatActivityConfig config = CatMgr.getConfig();
        int maxEnergy = config.getENERGY_LIMIT();
        boolean aboveMaxBefore = userData.getEnergy() >= maxEnergy;

        userData.setEnergy(userData.getEnergy() - count);

        if (aboveMaxBefore) {
            userData.setLastRecTime(System.currentTimeMillis());
        }

        SeasonTaskConditionData data = new SeasonTaskConditionData(BigInteger.valueOf((long)config.getActivityInfo().getType()), BigInteger.valueOf((long)count));
        player.notifyListener(eGamePlayerEventType.XiangMoCostStaminaTask.getValue(), data);
        // 体力日志
        AutoLogMgr.add(new LogCatActivityEnergy(userData.getUserId(), userData.getActivityId(), way, count, userData.getEnergy()));
        return true;
    }

    /**
     * 使用体力药
     */
    public int useEnergyItem(int count) {
        if (count <= 0 || count > 9999) {
            return GameErrorCode.E_GOURD_CHILD_ACTIVITY_USE_COUNT_ERROR;
        }
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        recoveryEnergy();

        Property cost = new Property();
        cost.addProperty(config.getENERGY_ITEM_ID(), BigInteger.valueOf(count));

        // 计算恢复数量
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(config.getENERGY_ITEM_ID());
        BigInteger energyCount = goodsInfo.getParamList().get(0);
        int totalCount = energyCount.intValue() * count;

        // 扣道具
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityEnergyItemConsume)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        // 加体力
        userData.setEnergy(userData.getEnergy() + totalCount);

        if (userData.getEnergy() > config.getENERGY_LIMIT()) {
            userData.setLastRecTime(System.currentTimeMillis());
        }

        CatProto.CatUseEnergyItemRespMsg.Builder builder = CatProto.CatUseEnergyItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEnergy(userData.getEnergy());
        builder.setLastRecTime(userData.getLastRecTime());
        player.sendPacket(Protocol.U_CAT_ITEM_USE, builder);

        //体力日志
        AutoLogMgr.add(new LogCatActivityEnergy(userData.getUserId(), userData.getActivityId(), 3, count, userData.getEnergy()));
        return 0;
    }

    /**
     * 神秘药箱：抽奖
     */
    public int draw(int type) {
        int times = 1;
        if(type == 1){
            times = 10;
        }else if(type == 2){
            times = 100;
        }

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(times == 100 && VipMgr.getVipLv(player.getUserInfo().getVipExp()) < config.getCAT_HUNDRED_EXTRACT_LIMIT()){
            return GameErrorCode.E_VIP_LEVEL_NO_ENOUGH;
        }

        //消耗
        Property consume = PropertyHelper.parseStringToProperty(config.getDrawConsumeList().get(type));
        //Property consume = PropertyHelper.parseStringToProperty(config.getSKIN_EXTRACT_ITEM_ID() + "="  + times);
        if(!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityDrawConsume)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        List<CatLottery> lotteryList = config.getLotteryList();
        List<Integer> weightList = new ArrayList<>();
        for (CatLottery lottery : lotteryList) {
            weightList.add(Integer.parseInt(lottery.getWeights()));
        }

        List<CatProto.CrossCatUploadNoticeReqMsg.Builder> uploadMsg = new ArrayList<>();

        Property reward = new Property();
        CatProto.CatLotteryDrawRespMsg.Builder respMsg = CatProto.CatLotteryDrawRespMsg.newBuilder();
        for (int i = 0; i < times; i++) {
            int idx = CatMgr.getRandomHelper().getSafeRandomIndexByWeight(weightList);
            CatLottery lottery = lotteryList.get(idx);
            reward.addProperty(PropertyHelper.parseStringToProperty(lottery.getRewards()));
            respMsg.addReward(lottery.getRewards());
            if(lottery.getIsBroadcast() == 1){
                CatProto.CrossCatUploadNoticeReqMsg.Builder builder = CatProto.CrossCatUploadNoticeReqMsg.newBuilder();
                builder.setActivityId(CatMgr.getActivityId());
                List<Integer> itemList = StringUtils.stringToIntegerList(lottery.getRewards(), "=");
                builder.setGoodsId(itemList.get(0));
                builder.setType(1);
                builder.setReward(lottery.getRewards());
                uploadMsg.add(builder);
            }
            AutoLogMgr.add(new LogCatActivityDraw(userData.getUserId(), userData.getActivityId(), lottery.getId(), lottery.getRewards()));
        }

        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.CatActivity, eLogMoneyType.CatActivityDrawReward);
        respMsg.setRet(0);
        player.sendPacket(Protocol.U_CAT_DRAW, respMsg);

        UserBaseInfo userBaseInfo = UserMgr.getUserBaseInfo(player.getUserId(), GameServer.getInstance().getServerId());
        PlayerProto.PlayerBaseTempMsg.Builder userBaseInfoBuilder = PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo);
        for (CatProto.CrossCatUploadNoticeReqMsg.Builder builder : uploadMsg) {
            builder.setPlayer(userBaseInfoBuilder);
            player.sendPacket(Protocol.C_CAT_ACTIVITY_UPLOAD_NOTICE, builder);
        }
        return 0;
    }


    //-----------------------------练习模式----------------------------------


    public int testChallenge(int passId) {

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(passId);
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_PASS_ID_ERROR;
        }

        GameData tempGameData = initGameData(userData, config, passId, true);
        //盘面数据重置
        if(!guide) {
            tempGameData.setBossBlood(config.getCAT_GUIDE_BOSS_POWER());
        }

        Element[][] elements = initElements(userData, config, tempGameData, true);
        userData.setTempCellData(elements);
        userData.setTempData(tempGameData);

        CatProto.CatTestChallengePassRespMsg.Builder respMsg = CatProto.CatTestChallengePassRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setStatus(CatActivityPb.parseCatGameStatusTemp(userData.getTempData()));
        respMsg.setGameData(CatActivityPb.getCellDataBuilder(userData.getTempCellData()));
        player.sendPacket(Protocol.U_CAT_CHALLENGE_TEST, respMsg);

        return 0;
    }

    public int testConnect(List<Position> positionList) {

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(userData.getTempData().getPass());
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }
        Position rolePosition = new Position(userData.getTempData().getRoleX(), userData.getTempData().getRoleY());

        //连线中的点不可重复
        List<Position> es = new ArrayList<>(positionList);
        es.add(rolePosition);
        if (checkConnectPositionValid(es)) return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;

        //复制盘面
        Element[][] tempElements = CatMgr.copy(userData.getTempCellData());
        GameData tempStatus = CatMgr.copy(userData.getTempData());

        //校验路径是否可达
        ConnectResult result = connect(rolePosition, positionList, tempElements, tempStatus, missionInfo);
        if(result.getRet() != 0){
            return result.getRet();
        }

        //盘面填充
        //加达摩
        initElementValue(result.getElements(), userData, config, missionInfo, tempStatus);

        //回合数+1
        tempStatus.setRound(tempStatus.getRound() + 1);

        //引导，第二回合
        if(!guide && tempStatus.getRound() == 2){
            Element element = result.getElements()[config.getCAT_GUIDE_ANGER_POSITION().getX()][config.getCAT_GUIDE_ANGER_POSITION().getY()];
            if(null == CatMgr.hasAttr(element, eElementAttrTypes.Anger.getType())) {
                EleAttr attr = new EleAttr();
                attr.setType(eElementAttrTypes.Anger.getType());
                element.getAttrs().add(attr);
            }
            guide = true;
        }
        //达摩愤怒
        angerDharma(result.getElements(), userData, config, missionInfo, result.getGameData());

        checkElementAllInit(result.getElements());

        userData.setTempCellData(result.getElements());
        userData.setTempData(result.getGameData());

        CatProto.CatTestGameConnectRespMsg.Builder respMsg = CatProto.CatTestGameConnectRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setStatus(CatActivityPb.parseCatGameStatusTemp(userData.getTempData()));
        respMsg.setGameData(CatActivityPb.getCellDataBuilder(userData.getTempCellData()));
        respMsg.setEnd(result.getGameData().isEnd());
        respMsg.setWin(result.getGameData().isWin());
        for (CatProto.CatConnectDetailTemp.Builder builder : result.getDetailBuilderList()) {
            respMsg.addDetail(builder);
        }
        for (int index : result.getWanNengList()) {
            Position position = CatMgr.coordinate(index);
            respMsg.addOmnipotentPoint(CatActivityPb.parsePoint(position.getX(), position.getY()));
        }
        for (int index : result.getNewMonsterList()) {
            Position position = CatMgr.coordinate(index);
            respMsg.addMonsterPoint(CatActivityPb.parsePoint(position.getX(), position.getY()));
        }
        for (CatProto.CatGameMoveHistoryTemp.Builder builder : result.getMoveList()) {
            respMsg.addMove(builder);
        }
        player.sendPacket(Protocol.U_CAT_CONNECTION_TEST, respMsg);

        return 0;
    }

    /**
     * 攻击主角（练习模式）
     */
    public int testAttackBoss() {

        if(userData == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        CatActivityConfig config = CatMgr.getConfig();
        if(config == null){
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData.getTempData().getAngerBar() < config.getPLAYER_SKILL_NEED_ANGER()){
            return GameErrorCode.E_CAT_ACTIVITY_ANGER_NO_ENOUGH;
        }

        CatMissionInfo missionInfo = config.getCatMissionInfoById(userData.getTempData().getPass());
        if(missionInfo == null){
            return GameErrorCode.E_CAT_ACTIVITY_CONFIG_NOT_FOUND;
        }

        GameData status = userData.getTempData();

        int times = status.getAngerBar() / config.getPLAYER_SKILL_NEED_ANGER();

        status.setAngerBar(status.getAngerBar() - times * config.getPLAYER_SKILL_NEED_ANGER());

        long damage = BigDecimal.valueOf(userData.getAbility()).multiply(BigDecimal.valueOf(times))
                .multiply(BigDecimal.valueOf(config.getCAT_PLAYER_SKILL_ATK_PARAMETER())).divide(BigDecimal.valueOf(1000L), 0, BigDecimal.ROUND_UP).longValue();

        status.setBossBlood(status.getBossBlood() - damage);
        status.setSkillDamage(status.getSkillDamage() + damage);

        CatProto.CatTestRoleAttackRespMsg.Builder respMsg = CatProto.CatTestRoleAttackRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setEnd(status.isEnd());
        respMsg.setWin(status.isWin());
        respMsg.setStatus(CatActivityPb.parseCatGameStatusTemp(userData.getTempData()));
        respMsg.setGameData(CatActivityPb.getCellDataBuilder(userData.getTempCellData()));
        player.sendPacket(Protocol.U_CAT_LAUNCH_TEST, respMsg);
        return 0;
    }


    public boolean checkElementAllInit(Element[][] elements){
        for (int i = 0; i < CatActivityConfig.ROW_NUM; i++) {
            for (int k = 0; k < CatActivityConfig.COLUMN_NUM; k++) {
                Element element = elements[k][i];
                if(element != null && element.getType() != -1){
                    continue;
                }
                CatMgr.getLogger().info("checkElementAllInit player {}, x : {}, y : {} is null", player.getUserId(), k, i);
                return false;
            }
        }
        return true;
    }

    public CatUserData getUserData() {
        return userData;
    }
}
